﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.Serialization;

namespace GesturePlugin
{
    [Serializable]
    public class Gesture
    {
        private string _name;
        private IList _gesturePatterns;

        public Gesture()
        {
            _gesturePatterns = new ArrayList();
        }

        public Gesture(string name) : this()
        {
            _name = name;
        }

        public Gesture(string name, IList gesturePatterns) : this()
        {
            _name = name;
            _gesturePatterns = gesturePatterns;
        }

        /// <summary>
        /// Gesture's name
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// List of patterns' gesture
        /// </summary>
        public IList GesturePatterns
        {
            get { return _gesturePatterns; }
            set { _gesturePatterns = value; }
        }

        /// <summary>
        /// Adds the pattern into the patterns list if it doesn't already exists
        /// </summary>
        /// <param name="pattern"></param>
        public void AddPattern(string pattern)
        {
            if (!_gesturePatterns.Contains(pattern))
            {
                _gesturePatterns.Add(pattern);
            }
        }

        //Levenshtein's algo
        /// -------------------------------------------------------------------------------------------
        /// <summary>
        /// Calculate the Levenshtein's distance.
        /// </summary>
        /// <returns> The Levenshtein's value. </returns>
        /// <remarks>
        /// The test is CASE SENSITVE !
        /// The cell result[i,j] of the matrix equal to the minimum of:
        /// a. The cell immediately above plus 1: result[i-1,j] + 1.
        /// b. The cell immediately to the left plus 1: result[i,j-1] + 1.
        /// c. The cell diagonally above and to the left plus the cost: result[i-1,j-1] + cost[i,j]
        /// </remarks>
        /// <param name="word1"> The first word (s). </param>
        /// <param name="word2"> The second word (t). </param>
        /// -------------------------------------------------------------------------------------------
        private int LevenshteinValue(string word1, string word2)
        {
            if (word1.Length == 0) return word2.Length;
            else if (word2.Length == 0) return word1.Length;
            else
            {
                List<int> lastColumn = new List<int>(word2.Length);
                for (int i = 1; i <= word2.Length; i++) lastColumn.Add(i);
                int lastValue = 0;
                int forLastValue = 0;

                // Get the minimum value
                for (int j = 1; j <= word1.Length; j++)
                {
                    for (int i = 0; i < word2.Length; i++)
                    {
                        int x = (i == 0 ? j : lastValue) + 1;
                        int y = lastColumn[i] + 1;
                        int z = (i == 0 ? j - 1 : lastColumn[i - 1]) + (word1[j - 1] == word2[i] ? 0 : 1);

                        forLastValue = lastValue;
                        lastValue = Math.Min(Math.Min(x, y), z);

                        if (i > 0) lastColumn[i - 1] = forLastValue;
                        if (i == word2.Length - 1) lastColumn[i] = lastValue;
                    }
                }
                return lastValue;
            }
        }

        /// <summary>
        /// Gets the best Levenshtein value between the drawing pattern and patterns in the list
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public int GetBestLevenshteinValue(string pattern)
        {
            int bestDiff = 100;

            if(_gesturePatterns.Count > 0)
            {
                for (int i = 0; i < _gesturePatterns.Count; i++)
                {
                    string gesturePattern = _gesturePatterns[i].ToString();
                    int diff = LevenshteinValue(gesturePattern, pattern);
                        
                    if (diff < bestDiff)
                    {
                        bestDiff = diff;
                    }
                }
            }
            return bestDiff;
        }

        public override string ToString()
        {
            return _name;
        }
    }
}
